home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume22 / crefine / part01 next >
Encoding:
Text File  |  1991-08-26  |  53.0 KB  |  1,553 lines

  1. Newsgroups: comp.sources.misc
  2. From: Lutz Prechelt <prechelt@i41s14.ira.uka.de>
  3. Subject:  v22i063:  crefine - C-Refine preprocessor, Part01/04
  4. Message-ID: <csm-v22i063=crefine.222259@sparky.imd.sterling.com>
  5. X-Md4-Signature: ad2ce72e818406e8bba5abec3b00b826
  6. Date: Mon, 26 Aug 1991 03:23:53 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Lutz Prechelt <prechelt@i41s14.ira.uka.de>
  10. Posting-number: Volume 22, Issue 63
  11. Archive-name: crefine/part01
  12. Environment: UNIX, MS-DOS, TOS, C, C++, Objective-C
  13.  
  14. C-Refine is a preprocessor for programs written in C or C++ or a similar
  15. language. It introduces an additional language construct called 'refinement'
  16. which allows further decomposition with symbolic names inside functions.
  17. This makes programs much easier to read and modify and is very comfortable
  18. for programming.
  19.  
  20. C-Refine should work with any language that closely resembles C-Syntax and
  21. with any operating system that supports C-style I/O (stdio.h)
  22.  
  23. The installed system consists of a single executable file (crefine) and one
  24. Unix Manualpage (crefine.1). No further data files or libraries
  25. except the standard C library are needed, so C-Refine is easily portable.
  26.  
  27.    Lutz 
  28.  
  29. Lutz Prechelt  (++49/721/608-4317, FAX: ++49/721/697760) | Whenever you 
  30. Institut fuer Programmstrukturen und Datenorganisation   | complicate things,
  31. Universitaet Karlsruhe;  D-7500 Karlsruhe 1;  Germany    | they get
  32. prechelt@ira.uka.de  or  prechelt!ira.uka.de@relay.csnet | less simple.
  33.  
  34. ----------------------------cut here-------------------------------------
  35. #! /bin/sh
  36. # This is a shell archive.  Remove anything before this line, then feed it
  37. # into a shell via "sh file" or similar.  To overwrite existing files,
  38. # type "sh file -c".
  39. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  40. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  41. # Contents:  README To_Do cr_getln.cr crefine.c
  42. # Wrapped by kent@sparky on Sun Aug 25 21:56:45 1991
  43. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  44. echo If this archive is complete, you will see the following message:
  45. echo '          "shar: End of archive 1 (of 4)."'
  46. if test -f 'README' -a "${1}" != "-c" ; then 
  47.   echo shar: Will not clobber existing file \"'README'\"
  48. else
  49.   echo shar: Extracting \"'README'\" \(3287 characters\)
  50.   sed "s/^X//" >'README' <<'END_OF_FILE'
  51. X/*
  52. X    Copyright (C) 1987-1991 by Lutz Prechelt, Karlsruhe
  53. X
  54. X    This program is free software; you can redistribute it and/or modify
  55. X    it under the terms of the GNU General Public License as published by
  56. X    the Free Software Foundation; either version 1, or (at your option)
  57. X    any later version.
  58. X    This program is distributed in the hope that it will be useful,
  59. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  60. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  61. X    GNU General Public License for more details.
  62. X    You should have received a copy of the GNU General Public License
  63. X    along with this program; if not, write to the Free Software
  64. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  65. X*/
  66. X
  67. X>>>>> This is README for C-Refine Version 2.4 <<<<<
  68. X
  69. XC-Refine is a preprocessor for programs written in C or C++ or a similar 
  70. Xlanguage. It introduces an additional language construct called 'refinement'
  71. Xwhich allows further decomposition with symbolic names inside functions.
  72. XThis makes programs much easier to read and modify and is very comfortable
  73. Xfor programming.
  74. X
  75. XThe system consists of a single executable file (crefine) and one
  76. XUnix Manualpage (crefine.1). No further data files or libraries 
  77. Xexcept the standard C library are needed.
  78. X
  79. X------------------------------------------------------------------------------
  80. X
  81. XTo generate C-Refine (which is bootstrapped, i.e. written in C-Refine)
  82. Xyou must first compile the preprocessed version of the files.
  83. X
  84. XThis is done with the command
  85. X  make crefine_from_c
  86. Xwhich always compiles and links all 4 parts.
  87. X
  88. XIf you have a working version of C-Refine you can bootstrap it via
  89. X  make crefine
  90. X
  91. XThe makefile also mentions a rule for translating in one step from
  92. XC-Refine to .o
  93. X
  94. X------------------------------------------------------------------------------
  95. X
  96. XIf you have gotten C-Refine to work on a machine not mentioned below,
  97. Xplease send me (prechelt@ira.uka.de) a short note of the form:
  98. X
  99. X   Subject: got C-Refine working
  100. X   I got C-Refine 2.4 to work without problems on the following machine
  101. X   <name-of-computer> <name-and-version-of-operating-system>
  102. X   
  103. X(...or describe why C-Refine didn't compile and perhaps send me a minimal
  104. Xdiff to get it to work.)
  105. X
  106. X------------------------------------------------------------------------------
  107. X
  108. XEnvironments where C-Refine already works:
  109. X
  110. X(CF is the certainty factor with the following meaning:
  111. X 1: compiles  (I have checked that)
  112. X 2: most probably compiles (but I don't have machine at hand to check again)
  113. X 3: probably compiles (it once did, but changes may have reversed this)
  114. X 4: should compile (have done my best from what I know about that system)
  115. X 5: may compile (a bit doubtful)
  116. X)
  117. XCF  Machine            Operating System (and perhaps Compiler)
  118. X
  119. X1   DECstation 3100    Ultrix 4.1
  120. X3   IBM PC etc.        MS-DOS 3.2 (Microsoft C 5.0)
  121. X3   PCS (type???)      (some System V)
  122. X2   Sun3               SUN-OS 3.5
  123. X1   Sun3,Sun4          SUN-OS 4.03
  124. X1   Sun3,Sun4          SUN-OS 4.1
  125. X1   VAXstation 3250    Ultrix-32 V3.1
  126. X
  127. X------------------------------------------------------------------------------
  128. X
  129. XThe Makefile will not work with some prehistoric versions of "make".
  130. XIn this case I strongly suggest that you get a newer make, e.g. GNU-Make.
  131. END_OF_FILE
  132.   if test 3287 -ne `wc -c <'README'`; then
  133.     echo shar: \"'README'\" unpacked with wrong size!
  134.   fi
  135.   # end of 'README'
  136. fi
  137. if test -f 'To_Do' -a "${1}" != "-c" ; then 
  138.   echo shar: Will not clobber existing file \"'To_Do'\"
  139. else
  140.   echo shar: Extracting \"'To_Do'\" \(475 characters\)
  141.   sed "s/^X//" >'To_Do' <<'END_OF_FILE'
  142. X Things to do in C-Refine     as of 22.08.91
  143. X==========================
  144. X
  145. X1. Lutz Prechelt, 11.06.91
  146. X   Handle #line directives in form (<ws> is whitespace, i.e. Blank or Tab)
  147. X   #[<ws>...][line<ws>...]<linenumber>[<ws>..."<filename>"]
  148. X   so e.g.
  149. X   #line 11 "abc.x"
  150. X   # 15 "abc.c"
  151. X
  152. X2. Lutz Prechelt, 11.06.91
  153. X   Handle stdin and stdout as files via "-" syntax
  154. X
  155. X3. Lutz Prechelt, 11.06.91
  156. X   Handle multiple input files:
  157. X   Enforce stripping of "r" at end of input file name
  158. END_OF_FILE
  159.   if test 475 -ne `wc -c <'To_Do'`; then
  160.     echo shar: \"'To_Do'\" unpacked with wrong size!
  161.   fi
  162.   # end of 'To_Do'
  163. fi
  164. if test -f 'cr_getln.cr' -a "${1}" != "-c" ; then 
  165.   echo shar: Will not clobber existing file \"'cr_getln.cr'\"
  166. else
  167.   echo shar: Extracting \"'cr_getln.cr'\" \(14951 characters\)
  168.   sed "s/^X//" >'cr_getln.cr' <<'END_OF_FILE'
  169. X/*************************************************************************
  170. XProject : C-Refine Precompiler
  171. XModule  : Line Scanner
  172. XAuthor  : Lutz Prechelt, Karlsruhe
  173. XDate    : 11.06.91  Version 16
  174. XCompiler: ANSI C
  175. X**************************************************************************/
  176. X/*
  177. X    Copyright (C) 1988,89,90,91 by Lutz Prechelt, Karlsruhe
  178. X
  179. X    This program is free software; you can redistribute it and/or modify
  180. X    it under the terms of the GNU General Public License as published by
  181. X    the Free Software Foundation; either version 1, or (at your option)
  182. X    any later version.
  183. X    This program is distributed in the hope that it will be useful,
  184. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  185. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  186. X    GNU General Public License for more details.
  187. X    You should have received a copy of the GNU General Public License
  188. X    along with this program; if not, write to the Free Software
  189. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  190. X*/
  191. X
  192. X/************************************************************************
  193. X*********************** C - R e f i n e *********************************
  194. X*************************************************************************/
  195. X
  196. X#include <stdio.h>
  197. X#include <string.h>
  198. X#include <ctype.h>
  199. X
  200. X#include "cr_decl.h"  /* globale Funktionen, Typen und Daten */
  201. X
  202. X/******************* lokale Funktionen ************************************/
  203. X
  204. Xstatic void  push_refinement_name A(());
  205. Xstatic int   normal_scanner A((LINE_INFO*));
  206. Xstatic int   comment_scanner A((LINE_INFO*));
  207. Xstatic int   text_scanner A((LINE_INFO*));
  208. Xstatic int   char_scanner A((LINE_INFO*));
  209. X
  210. X/*************************** defines ***************************************/
  211. X
  212. X#define push(ch) *(s++) = (char)ch
  213. X
  214. X#define leave_sequence    "leave"   /* e.g. "leave" (no leading blank!) */
  215. X#define leave_sequence_length  5
  216. X
  217. X#define normal_end_of_line       1   /* real end of line */
  218. X#define continueing_end_of_line  2   /* logical end of line */
  219. X#define refinementsymbol_found   3
  220. X#define leave_keyword_found      4
  221. X
  222. X/*********************** Lokale Daten ************************************/
  223. X
  224. X/***** one line buffer *****/
  225. Xstatic char *act;             /* current position in b */
  226. X
  227. X/***** Control *****/
  228. X#if ansi
  229. Xstatic int (*scanner) (LINE_INFO*) = normal_scanner;
  230. X#else
  231. Xstatic int (*scanner) ()           = normal_scanner;
  232. X#endif
  233. X/***** Status *****/
  234. Xstatic int  level = 0,                      /* brace-nesting */
  235. X            just_was = normal_end_of_line,  /* event memory */
  236. X            event = normal_end_of_line,
  237. X            semicolon_count,
  238. X            lines_in_denoter,
  239. X            old_indent;
  240. X
  241. X/*********************** get_line ****************************************/
  242. X
  243. Xextern void get_line (fp, l, semicolons)
  244. X  FILE       *fp;
  245. X  LINE_INFO  *l;
  246. X  int        *semicolons;  /* is increased only ! */
  247. X{
  248. X  /* Reads on line from file fp and sets up l accordingly.
  249. X     The preprocessed line is copied to *s and s is increased appropriately.
  250. X     (A null terminator is appended.)
  251. X     The line is a complete line only, if there is no refinement involved 
  252. X     with that line:
  253. X     For refinement calls and refinement declaration headers a separate line
  254. X     is generated.
  255. X     At end of file stop_processing is set to true. Problems yield a 
  256. X     message and let 'errors' or 'warnings' increase.
  257. X     This function uses the option indicator variables.
  258. X  */
  259. X  charp old_s = s;    /* store s to compute length later */
  260. X  bool stop = false;
  261. X  bool three_witches;
  262. X  semicolon_count = 0;
  263. X  `init l;
  264. X  if (just_was == normal_end_of_line) {
  265. X     `read line;
  266. X     `get indent;
  267. X  }
  268. X  else {                       /* continued line */
  269. X     l->indent = old_indent;
  270. X     l->line_no = line_no;
  271. X  }
  272. X  `handle line;
  273. X
  274. X`init l:
  275. X#if debug
  276. X  printf ("get_line:");
  277. X#endif
  278. X  l->level   = level;   /* level is defined as level at start of line! */
  279. X  l->start   = s;
  280. X  l->indent  = 0;
  281. X  l->type    = normal;
  282. X
  283. X`read line:
  284. X  l->line_no = ++line_no;
  285. X  act = (char*)fgets (b, b_size, fp);  /* get next line*/
  286. X#if debug
  287. X  printf ("->%s<-", act == NULL ? "(NULL)" : (char*)act);
  288. X#endif
  289. X  if (act == NULL) {                /* check for EOF */
  290. X     stop_processing = true;
  291. X     l->type = empty;
  292. X     if (level > 0)
  293. X        error (Eeof_brace, NULL, line_no);
  294. X     if (scanner == comment_scanner)
  295. X        error (Eeof_comment, NULL, line_no);
  296. X     if (scanner == text_scanner)
  297. X        error (Eeof_string, NULL, line_no);
  298. X     if (scanner == char_scanner)
  299. X        error (Eeof_char, NULL, line_no);
  300. X     return;
  301. X  }
  302. X
  303. X`get indent:
  304. X  while (!stop)
  305. X     if (*act == ' ') {
  306. X        l->indent++;
  307. X        act++;
  308. X     }
  309. X     else if (*act == TAB) {    /* expand Tabs */
  310. X        l->indent = (l->indent/tabsize + 1) * tabsize;
  311. X        act++;
  312. X     }
  313. X     else
  314. X        stop = true;
  315. X  old_indent = l->indent;    /* store for next call */
  316. X
  317. X`handle line:
  318. X  three_witches = l->indent == 0 && level > 0 && scanner == normal_scanner;
  319. X  if (three_witches && (int)*act == refinementsymbol)
  320. X       `handle_refinement_declaration;
  321. X  else {
  322. X     `check column 0;
  323. X     if (just_was != refinementsymbol_found &&
  324. X         just_was != leave_keyword_found)
  325. X        event = (*scanner) (l);
  326. X     `handle_event;
  327. X     if (option_small || event == normal_end_of_line)
  328. X       `delete trailing blanks;
  329. X  }
  330. X  l->length = s - old_s;
  331. X  if (l->length == 0)
  332. X     l->type = empty;
  333. X  push (0);  /* String Terminator */
  334. X  `perhaps warn for level changes;
  335. X  assert (!(l->type == refdecl && semicolon_count != 0));
  336. X  *semicolons += semicolon_count;
  337. X
  338. X`handle_refinement_declaration:
  339. X  act++;                     /* skip refinementsymbol */
  340. X  push_refinement_name ();
  341. X  if (*act != ':')
  342. X     error (Erefdecl_syntax, act, line_no);
  343. X  else
  344. X     act++;
  345. X  if (level > 1)
  346. X     error (Erefdecl_nested, NULL, line_no);
  347. X  l->type = refdecl;
  348. X  just_was = (*act == '\n' || *act == 0) ? normal_end_of_line :
  349. X                                           continueing_end_of_line;
  350. X
  351. X`check column 0:
  352. X  if (three_witches && !iscntrl (*act) &&
  353. X      just_was != continueing_end_of_line &&
  354. X      *act != '}' && *act != '#' && *act != '*' && *act != '/')
  355. X     warning (Wcol0, act, line_no, 1);
  356. X
  357. X`handle_event:
  358. X  if (event == refinementsymbol_found || event == leave_keyword_found)
  359. X     `handle refinementcall or leave;
  360. X  else
  361. X     just_was = normal_end_of_line;
  362. X
  363. X`handle refinementcall or leave:
  364. X  if (s - old_s == 0) {        /* line empty */
  365. X     push_refinement_name ();
  366. X     l->type = event == leave_keyword_found ? leave : refcall;
  367. X     `skip semicolon and blanks;
  368. X     just_was = (*act == 0 || *act == '\n') ? normal_end_of_line :
  369. X                                              continueing_end_of_line;
  370. X  }
  371. X  else
  372. X     just_was = event;
  373. X
  374. X`skip semicolon and blanks:
  375. X  if (*act == ';') {        /* skip semikolon if present */
  376. X     act++;
  377. X     semicolon_count++;
  378. X     if (l->type == refcall)
  379. X        l->type = refcallr;   /* note the removed ";" */
  380. X  }
  381. X  while (*(act++) == ' ')   /* skip following blanks */
  382. X          ;
  383. X  act--;                    /* recover char after last blank */
  384. X
  385. X`delete trailing blanks:
  386. X  while (*(s-1) == ' ')      /* remove trailing blanks */
  387. X     s--;
  388. X
  389. X`perhaps warn for level changes:
  390. X  int lev = level;
  391. X  if (lev < 0) {  /* Syntax error!  (or C-Refine does not work...) */
  392. X     if (option_anyway)
  393. X        error (Emany_braces, NULL, line_no);
  394. X     else
  395. X        fatal_error (Emany_braces, NULL, line_no);
  396. X  }
  397. X  else if (lev > 5 && level > l->level)
  398. X        warning (Wnesting, NULL, line_no, 3);
  399. X  else if (l->indent > 35 && `is refcall && !option_small)
  400. X        warning (Wmuch_indent, NULL, line_no, 3);
  401. X
  402. X`is refcall:
  403. X  l->type == refcall || l->type == refcallr
  404. X}
  405. X
  406. X/********************** push_refinement_name *******************************/
  407. X
  408. Xstatic void push_refinement_name ()
  409. X{
  410. X  /* reads input using 'act' and generates output using 's'.
  411. X     reads all following blanks, letters, digits and underscores (that is,
  412. X     stops on other characters) and generates from that a C identifier
  413. X     on the output by suppressing leading and trailing blanks.
  414. X     With option_ibmchars the Umlaute and Accentcharacters from the
  415. X     IBM International Charset are also allowed.
  416. X  */
  417. X#define is_legal(ch)  (isalnum(ch) || (ch) == ' ' || ch == '_' || \
  418. X                       (option_ibmchars && \
  419. X                           (((ch) >= 128 && (ch) <= 167)) || (ch) == 225))
  420. X  int ch;
  421. X  charp old_s = s, start = s;
  422. X  `suppress leading blanks;
  423. X  `copy legal chars;
  424. X  `suppress trailing blanks;
  425. X  assert (*(s-1) != ' ');
  426. X  assert (*old_s != ' ');
  427. X  assert (s - old_s >= 0);
  428. X  `change inner blanks to underlines;
  429. X  if (s - old_s == 0)
  430. X     error (Erefname_missing, act, line_no);
  431. X
  432. X`suppress leading blanks:
  433. X  while (*act == ' ')               /* suppress leading blanks */
  434. X     act++;
  435. X
  436. X`copy legal chars:
  437. X  do {                              /* copy legal chars */
  438. X    ch = *(act++);
  439. X    push (ch);
  440. X  }
  441. X  while (is_legal (ch));
  442. X  s--; act--;                       /* unpush illegal last char */
  443. X
  444. X`suppress trailing blanks:
  445. X  while (*(s-1) == ' ' && s > old_s) /* suppress trailing blanks */
  446. X     s--;
  447. X
  448. X`change inner blanks to underlines:
  449. X  for (start++; start < s; start++) /* change inner blanks to underlines */
  450. X     if (*start == ' ')
  451. X        *start = '_';
  452. X#undef is_legal
  453. X}
  454. X
  455. X/***********************  S C A N N I N G  *********************************/
  456. X
  457. X#define q    39      /* Quote */
  458. X#define dq   34      /* Double-Quote */
  459. X
  460. X/*********************** normal_scanner ***********************************/
  461. X
  462. Xstatic int normal_scanner (l)
  463. X  LINE_INFO *l;
  464. X{
  465. X  /* Changes to reading comments, strings or quoted chars as necessary.
  466. X     Ends only at the end of a line.
  467. X     Tries to identify refinement calls and refinement declarations;
  468. X     in these cases the lines are reduced to only the refinement name.
  469. X  */
  470. X  register int ch;
  471. X  for (;;) {
  472. X    ch = *(act++);
  473. X    switch (ch) {
  474. X      case '\n':
  475. X      case 0   : return (normal_end_of_line);
  476. X      case '/' : if (*act == '*')              /* start of comment ? */
  477. X                    `handle normal comment;
  478. X                 else if (*act == '/' && option_cplusplus)
  479. X                    `handle doubleslash style comment;
  480. X                 else                           /* No --> normal */
  481. X                    push (ch);
  482. X                 break;
  483. X      case dq  :
  484. X                 `handle text denoter;
  485. X      case q   :
  486. X                 `handle char denoter;
  487. X      case ';' : semicolon_count++;
  488. X                 push (';');
  489. X                 break;
  490. X      case '{' : level++;
  491. X                 push (ch);
  492. X                 break;
  493. X      case '}' : level--;
  494. X                 push (ch);
  495. X                 break;
  496. X      default  :
  497. X                 if (ch == refinementsymbol)
  498. X                   `check for leave or refinement call;
  499. X                 else
  500. X                   push (ch);
  501. X    }
  502. X  }
  503. X
  504. X`handle normal comment:
  505. X  if (!option_small) {
  506. X     push (ch); push ('*');
  507. X  }
  508. X  act++;
  509. X  scanner = comment_scanner;
  510. X  return ((*scanner) (l));
  511. X
  512. X`handle doubleslash style comment:
  513. X  if (option_small)
  514. X     return (normal_end_of_line);   /* just pgnore rest of line */
  515. X  push (ch); push (ch);             /*  put  //   */
  516. X  act++;
  517. X  while (*act != '\n' && *act != 0)   /* put rest of line */
  518. X     push (*(act++));
  519. X  return (normal_end_of_line);
  520. X
  521. X`handle text denoter:
  522. X  push (ch);
  523. X  scanner = text_scanner;
  524. X  lines_in_denoter = 0;
  525. X  return ((*scanner) (l));
  526. X
  527. X`handle char denoter:
  528. X  push (ch);
  529. X  scanner = char_scanner;
  530. X  lines_in_denoter = 0;
  531. X  return ((*scanner) (l));
  532. X
  533. X`check for leave or refinement call :
  534. X  /* Precondition: Refinement symbol found, 'act' is right behind it.
  535. X     if a 'leave' surrounded by blanks is found in front of the 
  536. X     refinement symbol, it and its blanks are stripped and 
  537. X     leave_keyword_found is returned.
  538. X     Otherwise refinementsymbol_found gemeldet is returned
  539. X  */
  540. X  charp old_s = s--;
  541. X  while (*s == ' ')
  542. X     s--;
  543. X  s++;
  544. X  if (!memcmp (s - leave_sequence_length, leave_sequence,
  545. X               leave_sequence_length)) {
  546. X     s -= leave_sequence_length;     /* Remove leave_sequence from Output */
  547. X     return (leave_keyword_found);
  548. X  }
  549. X  else {
  550. X     s = old_s;
  551. X     return (refinementsymbol_found);
  552. X  }
  553. X}
  554. X
  555. X/********************* comment_scanner *************************************/
  556. X
  557. Xstatic int comment_scanner (l)
  558. X  LINE_INFO *l;
  559. X{
  560. X  /* Precondition: position is right behind a start of a comment 
  561. X     (which is already copied if not option_small is true)
  562. X     Postcondition: position is right after a comment end.
  563. X  */
  564. X  register int ch;
  565. X  for (;;) {
  566. X    ch = *(act++);
  567. X    switch (ch) {
  568. X      case '\n':
  569. X      case 0   : return (normal_end_of_line);
  570. X      case '*' : if (*act == '/')       /* end of comment : */
  571. X                    `handle comment end;
  572. X                 /* no break ! */
  573. X      default  : if (!option_small)
  574. X                    push (ch);
  575. X    }
  576. X  }
  577. X
  578. X`handle comment end:
  579. X  if (!option_small) {
  580. X     push (ch); push ('/');
  581. X  }
  582. X  act++;
  583. X  scanner = normal_scanner;   /* change to normal scanner */
  584. X  return ((*scanner) (l));    /* and continue scanning */
  585. X
  586. X}
  587. X
  588. X/********************* text_scanner *************************************/
  589. X
  590. Xstatic int text_scanner (l)
  591. X  LINE_INFO *l;
  592. X{
  593. X  /* Precondition: position is right behind the (already copied) 
  594. X                   double quote that starts a string denoter 
  595. X                   (string literal)
  596. X     Postcondition:position is right behind the closing double
  597. X                   quote of a string denoter
  598. X  */
  599. X  register int ch;
  600. X  lines_in_denoter++;
  601. X  for (;;) {
  602. X    ch = *(act++);
  603. X    switch (ch) {
  604. X      case '\n':
  605. X      case 0   : return (normal_end_of_line);  /* allowed ??? */
  606. X      case dq  : `end of stringdenoter;
  607. X      case '\\': push (ch);
  608. X                 if (*act == dq || *act == '\\') {
  609. X                    push (*act);
  610. X                    act++;
  611. X                 }
  612. X                 break;
  613. X      default  : push (ch);
  614. X    }
  615. X }
  616. X
  617. X`end of stringdenoter:
  618. X  push (ch);
  619. X  if (lines_in_denoter > 1)
  620. X     warning (Wlong_string, act-1, line_no,
  621. X              lines_in_denoter > 5 ? 1 : 2);
  622. X  scanner = normal_scanner;
  623. X  return ((*scanner) (l));
  624. X
  625. X}
  626. X
  627. X/********************* char_scanner *************************************/
  628. X
  629. Xstatic int char_scanner (l)
  630. X  LINE_INFO *l;
  631. X{
  632. X  /* Is analogous to text scanner, but uses single quote instead of double
  633. X     quote.
  634. X  */
  635. X  int ch;
  636. X  lines_in_denoter++;
  637. X  for (;;) {
  638. X    ch = *(act++);
  639. X    switch (ch) {
  640. X      case '\n':
  641. X      case 0   : return (normal_end_of_line);  /* allowed ??? */
  642. X      case q   : `end of chardenoter;
  643. X      case '\\': push (ch);
  644. X                 if (*act == q || *act == '\\') {
  645. X                    push (*act);
  646. X                    act++;
  647. X                 }
  648. X                 break;
  649. X      default  : push (ch);
  650. X    }
  651. X  }
  652. X
  653. X`end of chardenoter:
  654. X  push (ch);
  655. X  if (lines_in_denoter > 1)
  656. X     warning (Wlong_char, act-1, line_no,
  657. X              lines_in_denoter > 5 ? 1 : 2);
  658. X  scanner = normal_scanner;
  659. X  return ((*scanner) (l));
  660. X
  661. X}
  662. X
  663. END_OF_FILE
  664.   if test 14951 -ne `wc -c <'cr_getln.cr'`; then
  665.     echo shar: \"'cr_getln.cr'\" unpacked with wrong size!
  666.   fi
  667.   # end of 'cr_getln.cr'
  668. fi
  669. if test -f 'crefine.c' -a "${1}" != "-c" ; then 
  670.   echo shar: Will not clobber existing file \"'crefine.c'\"
  671. else
  672.   echo shar: Extracting \"'crefine.c'\" \(30121 characters\)
  673.   sed "s/^X//" >'crefine.c' <<'END_OF_FILE'
  674. X
  675. X/*************************************************************************
  676. XProject : C-Refine Precompiler
  677. XModule  : main module
  678. XAuthor  : Lutz Prechelt, Karlsruhe
  679. XDate    : 10.06.91  Version 16
  680. XCompiler: ANSI C, C-Refine 2.3 (bootstrapped)
  681. X**************************************************************************/
  682. X/*
  683. X    Copyright (C) 1988,89,90,91 by Lutz Prechelt, Karlsruhe
  684. X
  685. X    This program is free software; you can redistribute it and/or modify
  686. X    it under the terms of the GNU General Public License as published by
  687. X    the Free Software Foundation; either version 1, or (at your option)
  688. X    any later version.
  689. X    This program is distributed in the hope that it will be useful,
  690. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  691. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  692. X    GNU General Public License for more details.
  693. X    You should have received a copy of the GNU General Public License
  694. X    along with this program; if not, write to the Free Software
  695. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  696. X*/
  697. X
  698. X/************************************************************************
  699. X*********************** C - R e f i n e *********************************
  700. X*************************************************************************/
  701. X
  702. X#if 0
  703. XREMARK:
  704. X  This program was originally written using german identifiers and
  705. X  comments. I worked through it to change this (at least in most parts)
  706. X  but please do not flame me if there are relicts from this state.
  707. X  I did not find a sensible replacement for the german word 'Klammer' that
  708. X  may stand for any of the characters ( ) [ ] { }  so sometimes I still
  709. X  use the german one.
  710. X
  711. XVariants:
  712. X#define deutsch   fuer deutsche Meldungen statt englische
  713. X#define ms_dos    for  MS-DOS Operating System (Compiler Microsoft C 5.0)
  714. X#define unix      for  Unix
  715. X#define vms       for  VMS
  716. X#define ansi      for  ANSI-C Compiler
  717. X
  718. XFor version changes see refinement startup message and file cr_texts.h
  719. X
  720. X============================== History: ====================================
  721. X
  722. X
  723. XVersion 1.0  (Alpha)    (0, 1)
  724. X
  725. X1987
  726. X  procedural refinements only
  727. X  not comfortable, few error messages
  728. X
  729. X
  730. XVersion 2.0  (Alpha)    (2, 3)
  731. X
  732. XFeb. 88
  733. X  value-returning refinements,
  734. X  improved error handling,
  735. X  Options comment, feedback, list, numbering, refinementsymbol, small
  736. X
  737. X
  738. XVersion 2.1  (Beta)     (4, 5)
  739. X
  740. X09.04.88  ( --> Martin, Ihno, Volker, Beat)
  741. X  improved error handling
  742. X  triple error messages (german, english, german nonsense),
  743. X  Context description in error messages,
  744. X  Options anyway, feedback, ibm chars, message type, tabsize, warning level
  745. X  Expires 31.07.88
  746. X
  747. X
  748. XVersion 2.2             (6, 7, 8)
  749. X
  750. X08.07.88   ( --> Martin)
  751. X  corr: Changes blanks in namen to underscrores again (like in Version 1.0)
  752. X        (otherwise error in goto occur)
  753. X  corr: Removed semicolon after value-returning refinements kept
  754. X        (via introduction of refcallr)
  755. X  improved error handling: Warning for "often used" only for
  756. X  "big" refinements.
  757. X03.08.88
  758. X  corr: When inserting file names in "#line"-commands, backslashes
  759. X        are doubled (backslash is Escape symbol in C string denoters)
  760. X13.09.88
  761. X  corr: empty refinements will not give syntax errors anymore.
  762. X
  763. X
  764. XVersion 2.3             (9, 10, 11, 12, 13)
  765. X
  766. X29.09.88 ( --> Martin, Ihno)
  767. X  corr: refinements with just 1 semicolon are enclosed in braces also
  768. X        (to avoid "else"-conflict)
  769. X  C++ Mode (i.e. // Kommentare) as option p
  770. X17.03.89
  771. X  "std.h" introduced,  #ifdefs for environment switches introduced.
  772. X  Look-through, further "refinementized", several small corrections
  773. X  ported to SUN-OS (Berkeley-Unix)
  774. X  Size restrictions released (500 -> 800 lines, 50 -> 100 Refinements)
  775. X18.03.89
  776. X  dito, expires 31.07.89
  777. X11.09.89
  778. X  ported to PCS maschine under Munix 5.3 (System V)
  779. X  further #ifdefs for deutsch, expire
  780. X  The switches are given in the Makefile
  781. X11.09.89
  782. X  dito, expires 31.10.89
  783. X
  784. X
  785. XVersion 2.4             (14, 15, 16)
  786. X
  787. X27.08.90 ( --> Uni)
  788. X  Line numbering switchable in 4 levels.
  789. X  Quiet-Option
  790. X  Buffersizes selectable via option.
  791. X  New name handling for input/output files
  792. X
  793. X23.01.91 ( --> Uni, Usenet announcement, iraun1)
  794. X  Names and Comments changed to english (was german before)
  795. X  error in level switching of line numbering fixed.
  796. X
  797. X10.06.91 ()
  798. X  History translated to english
  799. X  some small corrections
  800. X  corr: REF_INFO storage has to be 0-initialized,
  801. X        so use calloc instead of malloc
  802. X  Eliminated duplication of function declarations for ansi and non-ansi
  803. X  by introduction of the A(a) macro in std.h
  804. X
  805. X=============================================================================
  806. X#endif
  807. X
  808. X#include <stdio.h>
  809. X#include <string.h>
  810. X#include <malloc.h>
  811. X#include <time.h>
  812. X
  813. X#define DATA_HERE     /* Here the data declarations are NOT extern */
  814. X#include "cr_decl.h"  /* global Functions, Types and Data */
  815. X#include "getargs.h"
  816. X
  817. X
  818. X/******************* lokal Functions ************************************/
  819. X
  820. Xextern int  main A((int argc,  charp *argv));
  821. Xextern int  crefine A((int argc, charp *argv));
  822. Xstatic void process_c_refine A((FILE *in, FILE *out));
  823. Xstatic void process_line A((FILE *out, int semicolons));
  824. Xstatic void insert_refinements A((FILE *out));
  825. Xstatic void insert_refinement A((FILE *out, LINE_INFO *l, int startindent,
  826. X                               int recursive_level));
  827. Xstatic void line_cmd A((FILE* out, int nr, int indent, int min_level));
  828. Xstatic void put_indent A((FILE *out, int how_much));
  829. Xstatic void put_line A((FILE *out, LINE_INFO *line, int additional_indent,
  830. X                      int min_linenumbering_level));
  831. Xstatic int  refinement_nr A((char *refinementname));
  832. Xstatic void allocate A((charp *buffer, unsigned *size, unsigned minsize));
  833. Xstatic void copy_with_doubled_backslashes A((char *string, char *copy));
  834. Xstatic void do_expire A((int day, int month, int year_in_century));
  835. Xstatic void reset_l_r_s A((void));
  836. X
  837. X/*********************** Lokal Data ************************************/
  838. X
  839. X/***** line info, refinement info *****/
  840. Xstatic LINES l;           /* line info */
  841. Xstatic int   l_pos;
  842. X
  843. Xstatic REFS  r;           /* refinement info */
  844. Xstatic int   r_pos;
  845. X
  846. X/***** Status *****/
  847. Xstatic int   old_level,          /* level at line before */
  848. X             commanded_line_no;  /* line_no according to last line_cmd */
  849. X
  850. X/***** Sonstiges *****/
  851. Xstatic char  blanks[] =  /* indents are made from this. */
  852. X  "                                                                       ";
  853. X/* "blanks" is taken as  72 Blanks long (see put_indent) */
  854. X
  855. Xstatic option_msg;
  856. X
  857. X#define refdecl_line(i)  /* line no of refinement head of r[i] */\
  858. X                          (l [r[i].firstentry].line_no)
  859. X
  860. X/******************************** crefine *********************************/
  861. X
  862. Xextern int main (argc, argv)      /* MAIN */
  863. X  int   argc;
  864. X  charp argv[];
  865. X{
  866. X  return (crefine (argc, argv));
  867. X}
  868. X
  869. Xstatic ARG argtab[] = {
  870. X#if  deutsch
  871. X  {'a', BOOLEAN, &option_anyway,
  872. X   "alle: Ausgabedatei trotz Fehlern nicht loeschen" },
  873. X  {'c', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  874. X  {'e', BOOLEAN, &option_indent,   "#line Kommandos einruecken" },
  875. X  {'f', BOOLEAN, &option_feedback, "Fortschrittsanzeige (Zeilennummern)" },
  876. X#if ms_dos
  877. X  {'I', BOOLEAN, &option_ibmchars,
  878. X   "erlaube IBM internationale Zeichen fuer Namen" },
  879. X#endif
  880. X  {'k', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  881. X  {'l', BOOLEAN, &option_list,     "liste alle Refinementnamen" },
  882. X  {'m', CHARACTER, &option_msg,
  883. X   "Meldungen in: d=deutsch, e=english, sonst humorig" },
  884. X  {'n', INTEGER, &numbering_level,
  885. X   "Stufe der Numerierung mit #line Kommandos" },
  886. X  {'p', BOOLEAN, &option_cplusplus,"C++ Modus" },
  887. X  {'q', BOOLEAN, &option_cplusplus,"keine Startmeldung ausgeben" },
  888. X  {'r', CHARACTER, &refinementsymbol, "Refinementsymbol (als Zeichen)" },
  889. X  {'R', INTEGER, &refinementsymbol, "Refinementsymbol (als Zahl)" },
  890. X  {'s', BOOLEAN, &option_small,    "strippen: Kompaktifizierte Ausgabe" },
  891. X  {'w', INTEGER, &warning_level,   "Warnstufe (0 - 3)" }
  892. X  {'F', INTEGER, &maxerrors,       "Max. Anzahl Fehler" },
  893. X  {'L', INTEGER, &b_size,          "Max. Zeilenlaenge" },
  894. X  {'N', INTEGER, &maxref,          "Max. Refinements je Funktion" },
  895. X  {'P', INTEGER, &s_size,          "Codepuffer in Bytes" },
  896. X  {'T', INTEGER, &tabsize,         "Tabulatorgroesse" },
  897. X  {'W', INTEGER, &maxwarnings,     "Max. Anzahl Warnungen" },
  898. X  {'Z', INTEGER, &maxline,         "Max. Zeilen je Funktion" },
  899. X#else
  900. X  {'a', BOOLEAN, &option_anyway,   "anyway: don't delete output on errors" },
  901. X  {'c', BOOLEAN, &option_comment,  "comment refinement names in output" },
  902. X  {'f', BOOLEAN, &option_feedback, "feedback that you work" },
  903. X  {'i', BOOLEAN, &option_indent,   "indent the #line commands" },
  904. X#if ms_dos
  905. X  {'I', BOOLEAN, &option_ibmchars,
  906. X   "enable IBM International Charset for names" },
  907. X#endif
  908. X  {'l', BOOLEAN, &option_list,     "list all refinement names" },
  909. X  {'m', CHARACTER, &option_msg,
  910. X   "Messages in: g=german, e=english, else sense of humor ?" },
  911. X  {'n', INTEGER, &numbering_level,
  912. X   "level of numbering with #line commands" },
  913. X  {'p', BOOLEAN, &option_cplusplus,"C++ mode" },
  914. X  {'q', BOOLEAN, &option_quiet,    "quiet mode (no startup message)" },
  915. X  {'r', CHARACTER, &refinementsymbol, "refinementsymbol (character form)" },
  916. X  {'R', INTEGER, &refinementsymbol, "refinementsymbol (decimal form)" },
  917. X  {'s', BOOLEAN, &option_small,    "small compactified output" },
  918. X  {'w', INTEGER, &warning_level,   "warning level (0 - 3)" },
  919. X  {'B', INTEGER, (int*)&s_size,    "code buffer in bytes" },
  920. X  {'E', INTEGER, &maxerrors,       "max errors" },
  921. X  {'L', INTEGER, (int*)&maxline,   "max lines per function" },
  922. X  {'N', INTEGER, (int*)&maxref,    "max refinements per function" },
  923. X  {'T', INTEGER, &tabsize,         "tab size" },
  924. X  {'W', INTEGER, &maxwarnings,     "max warnings" },
  925. X#endif
  926. X};
  927. X
  928. X
  929. Xextern int crefine (argc, argv)    /* C-REFINE */
  930. X  int   argc;
  931. X  charp argv[];
  932. X{
  933. X  /* Analyses options and opens files.
  934. X     Then calls  process_c_refine and closes files again.
  935. X     Returns the number of errors that have been found
  936. X  */
  937. X  bool two_filenames_given;
  938. X  int  wrong_options;
  939. X  FILE *in, *out;
  940. X  {   /* analysis_of_options  (Level 1) */
  941. X  option_anyway = option_feedback = option_indent = option_comment
  942. X                = option_list = option_ibmchars = option_cplusplus
  943. X                = false;
  944. X  option_small = true;
  945. X  numbering_level = 3;
  946. X#if deutsch
  947. X  option_msg  = 'd';
  948. X  msg_type    =  0;  /* deutsche Meldungen als Standard */
  949. X#else
  950. X  option_msg  = 'e';
  951. X  msg_type    =  1;  /* english warnings and errors as default */
  952. X#endif
  953. X  refinementsymbol = std_refinementsymbol;
  954. X  tabsize          = 1;
  955. X  warning_level    = 3;
  956. X  maxline          = STD_MAXLINE;
  957. X  maxref           = STD_MAXREF;
  958. X  b_size           = STD_MAXLINELENGTH;
  959. X  s_size           = STD_S_SIZE;
  960. X  maxerrors        = STD_MAXERRORS;
  961. X  maxwarnings      = STD_MAXWARNINGS;
  962. X  wrong_options = getargs (&argc, argv, argtab, ARGTABSIZE (argtab));
  963. X  if (option_small) {
  964. X     tabsize = 1;
  965. X  }
  966. X  if (option_msg == 'd' || option_msg == 'D' ||
  967. X      option_msg == 'g' || option_msg == 'G')
  968. X     msg_type = 0;
  969. X  else if (option_msg == 'e' || option_msg == 'E')
  970. X     msg_type = 1;
  971. X  else
  972. X     msg_type = 2;
  973. X  two_filenames_given = argc == 3;
  974. X  }
  975. X  if (wrong_options || argc>>1 != 1) {
  976. X     print_usage (argv[0], usagestring[msg_type],
  977. X                  argtab, ARGTABSIZE (argtab));
  978. X    {   /* startup_message  (Level 1) */
  979. X    fprintf (stderr,
  980. X             "C-Refine Precompiler   %s\n", versionstring[msg_type]);
  981. X    fprintf (stderr,
  982. X             "Copyright (C) 1988,89,90,91  Lutz Prechelt, Karlsruhe\n");
  983. X    }
  984. X     exit (100);
  985. X  }
  986. X  if (!option_quiet)
  987. X    {   /* startup_message  (Level 1) */
  988. X    fprintf (stderr,
  989. X             "C-Refine Precompiler   %s\n", versionstring[msg_type]);
  990. X    fprintf (stderr,
  991. X             "Copyright (C) 1988,89,90,91  Lutz Prechelt, Karlsruhe\n");
  992. X    }
  993. X  {   /* open_files_and_complain_if_necessary  (Level 1) */
  994. X  strcpy (name_in, argv[1]);            /* get */
  995. X#if ms_dos
  996. X  in = fopen (name_in, "rt");  /* read, translated mode */
  997. X#else
  998. X  in = fopen (name_in, "r");  /* read */
  999. X#endif
  1000. X  if (in == NULL || ferror (in)) {
  1001. X     fprintf (stderr, Eopen[msg_type], name_in);
  1002. X     exit (100);
  1003. X  }
  1004. X  copy_with_doubled_backslashes (name_in, modified_name_in);
  1005. X  if (two_filenames_given) {            /* if second name given */
  1006. X     strcpy (name_out, argv[2]);        /* take it as it is */
  1007. X  }
  1008. X  else {                                /* else */
  1009. X     strcpy (name_out, argv[1]);        /* take first name */
  1010. X     if (name_out[strlen(name_out)-1] == 'r')
  1011. X       name_out[strlen(name_out)-1] = 0; /* remove 'r' from end */
  1012. X     else
  1013. X       strcat (name_out, "RRR");         /* or append 'RRR' */
  1014. X  }
  1015. X#if ms_dos
  1016. X  out = fopen (name_out, "wt");  /* write, translated mode */
  1017. X#else
  1018. X  out = fopen (name_out, "w");  /* write */
  1019. X#endif
  1020. X  if (out == NULL || ferror (out)) {
  1021. X     fprintf (stderr, Eopen[msg_type], name_out);
  1022. X     exit (100);
  1023. X  }
  1024. X  }
  1025. X  {   /* reserve_memory_and_complain_if_necessary  (Level 1) */
  1026. X  b      = malloc (b_size);
  1027. X  r      = (REFS)calloc ((maxref+1), sizeof (REF_INFO));
  1028. X  l      = (LINES)malloc ((maxline+1) * sizeof (LINE_INFO));
  1029. X  s_root = malloc (s_size);
  1030. X  if (!(b && s_root && r && l)) {
  1031. X     fprintf (stderr, Ememory[msg_type]);
  1032. X     exit (100);
  1033. X  }
  1034. X  }
  1035. X  /* here we go: */
  1036. X  rewind (in);  /* Begin at the beginning, then proceed until you come */
  1037. X                /* to the end, there stop.   (from: Alice in Wonderland) */
  1038. X  process_c_refine (in, out);
  1039. X  fclose (in);
  1040. X  fclose (out);   /* Schliessen vor unlink noetig ! */
  1041. X  if (errors && !option_anyway) /* don't produce errorneous outputfiles */
  1042. X     unlink (name_out);         /* delete file */
  1043. X  if (errors || warnings)
  1044. X#if deutsch
  1045. X     fprintf (stderr, "%d Fehler%s   %d Warnung%s   Ausgabedatei %s\n",
  1046. X              errors,   errors   != 1 ? "" : "",
  1047. X              warnings, warnings != 1 ? "en" : "",
  1048. X              errors && !option_anyway ?
  1049. X                 "geloescht" : (errors ? "dennoch erhalten"
  1050. X                                       : "ist fragwuerdig"));
  1051. X#else
  1052. X     fprintf (stderr, "%d error%s   %d warning%s   Output %s\n",
  1053. X              errors,   errors   != 1 ? "s" : "",
  1054. X              warnings, warnings != 1 ? "s" : "",
  1055. X              errors && !option_anyway ?
  1056. X                 "deleted" : (errors ? "kept anyway" : "is doubtful"));
  1057. X#endif
  1058. X  return (errors);
  1059. X}
  1060. X
  1061. X/************************ process_c_refine *********************************/
  1062. X
  1063. Xstatic void process_c_refine (in, out)
  1064. X  FILE *in, *out;
  1065. X{
  1066. X  /* Reads the file 'in' to the end line by line via 'get_line' and
  1067. X     generates the C source code by inserting the refinement bodies for
  1068. X     the calls.
  1069. X     Generates error messages for undeclares refinements and warnings for
  1070. X     unused or often used ones.
  1071. X     Uses the variables stop_processing, errors, warnings,
  1072. X     s, l, r and the option indicators.
  1073. X  */
  1074. X  commanded_line_no = line_no = 0;
  1075. X  reset_l_r_s ();
  1076. X  if (numbering_level > 0)
  1077. X    /* we get a linefeed anyway! */
  1078. X    fprintf (out, "#line 1 \"%s\"", modified_name_in);
  1079. X  while (!stop_processing)
  1080. X     {   /* handle_next_line  (Level 1) */
  1081. X     int semicolons = 0;
  1082. X     if (option_feedback && line_no % FEEDBACK_INTERVAL == 0)
  1083. X        cout (line_no);
  1084. X     if (ferror (in))
  1085. X        fatal_error (Ereadinput, l[l_pos-1].start, line_no);
  1086. X     if (ferror (out))
  1087. X        fatal_error (Ewriteoutput, NULL, line_no);
  1088. X     get_line (in, l+l_pos, &semicolons);
  1089. X     process_line (out, semicolons);
  1090. X     }
  1091. X  if (option_feedback)
  1092. X     cout (line_no);
  1093. X  free (s_root);
  1094. X}
  1095. X
  1096. X/************************** process_line ************************************/
  1097. X
  1098. Xstatic void process_line (out, semicolons)
  1099. X  FILE *out;
  1100. X  int   semicolons;
  1101. X{
  1102. X  /* Works on the lines up to the current line l[l_pos] in the way that
  1103. X     it decides whether a function has ended and thus the insertion of
  1104. X     refinements has to be started.
  1105. X     On level 0 all lines are copied from in to out immediately.
  1106. X     After a state change from level 0 to level 1 all lines (along with
  1107. X     a lineinfo) are kept until the next transition to level 0 and the
  1108. X     refinement info is being built.
  1109. X     If necessary, error messages for overflow or refinement errors and
  1110. X     warnings for not or multiply used refinements are generated.
  1111. X  */
  1112. X  if (r_pos > 0)
  1113. X     r[r_pos - 1].semicolons += semicolons;
  1114. X  if (old_level == 0)
  1115. X     {   /* we_came_from_level_0  (Level 1) */
  1116. X     assert (l_pos == 0);   /* nothing can be stored from level 0 */
  1117. X     if (l[0].level == 0 || stop_processing)
  1118. X        {   /* remains_on_level_0_so_just_copy_it  (Level 2) */
  1119. X        if (l[0].type != normal && l[0].type != empty)
  1120. X           error (Elevel0_ref, l[0].start, line_no);
  1121. X        put_line (out, &l[0], 0, 1);
  1122. X        reset_l_r_s ();
  1123. X        }
  1124. X     else
  1125. X        {   /* function_has_begun  (Level 2) */
  1126. X        error_in_this_function = false;
  1127. X        old_level = l[0].level;    /* neuen Level merken */
  1128. X        if (l[0].type == refdecl && r_pos < maxref) {  /* empty function */
  1129. X           r[r_pos].name         = l[0].start;
  1130. X           r[r_pos].firstentry   = 0;
  1131. X           r[r_pos].active       = false;
  1132. X           r[r_pos++].semicolons = 0;
  1133. X           warning (Wempty_function, NULL, line_no - 1, 3);
  1134. X        }
  1135. X        l_pos++;                   /* store line */
  1136. X        }
  1137. X     }
  1138. X  else
  1139. X     {   /* we_were_inside_a_function_or_so  (Level 1) */
  1140. X     if (l[l_pos].level == 0 || stop_processing)
  1141. X        {   /* but_now_we_are_outside  (Level 2) */
  1142. X        insert_refinements (out);
  1143. X        put_line (out, &l[l_pos-1], 0, 1);  /* last line (Blockklammer) */
  1144. X        put_line (out, &l[l_pos], 0, 1);    /* the level 0 line */
  1145. X        error_in_this_function = false;
  1146. X        reset_l_r_s ();
  1147. X        }
  1148. X     else
  1149. X        {   /* and_still_keep_being_in  (Level 2) */
  1150. X        if (l[l_pos].type == refdecl && r_pos < maxref) {
  1151. X           r[r_pos].name         = l[l_pos].start;   /* enter Refinement */
  1152. X           r[r_pos].active       = false;
  1153. X           r[r_pos].firstentry   = l_pos;
  1154. X           r[r_pos++].semicolons = 0;
  1155. X        }
  1156. X        old_level = l[l_pos].level;/* store new level */
  1157. X        l_pos++;                   /* store line */
  1158. X        if (l_pos >= maxline)
  1159. X           fatal_error (Elines_in_func, l[l_pos].start, line_no);
  1160. X        if (s - s_root >= s_size - 150)  /* Reserve too small */
  1161. X           fatal_error (Ebytes_in_func, l[l_pos].start, line_no);
  1162. X        }
  1163. X     }
  1164. X}
  1165. X
  1166. X/************************ insert_refinements ******************************/
  1167. X
  1168. Xstatic void insert_refinements (out)
  1169. X  FILE *out;
  1170. X{
  1171. X  /* Replaces the refinement calls with the bodies, after the whole function
  1172. X     has been read in.
  1173. X     In the output #line statements are generated, except if option
  1174. X     numbering_level is zero.
  1175. X     Comments and indentations are thrown away if option_small is true.
  1176. X     Comments stating the refinement names are inserted in the output if
  1177. X     option_comment is true.
  1178. X  */
  1179. X  int  i, end;
  1180. X  bool extern_stop = stop_processing;  /* Protect last function against */
  1181. X  stop_processing  = false;            /* local use of this variable */
  1182. X  r[r_pos].firstentry = l_pos-1;       /* line of Blockklammer */
  1183. X  r[r_pos].name       = NULL;
  1184. X  {   /* generate_refinement_list_if_necessary  (Level 1) */
  1185. X  if (option_list && r_pos > 0) {
  1186. X     fputc ('\n', stdout);
  1187. X     for (i = 0; i < r_pos; i++)
  1188. X         fprintf (stdout, "(%d) %s\n", refdecl_line (i), r[i].name);
  1189. X  }
  1190. X  }
  1191. X  {   /* find_last_line_to_insert  (Level 1) */
  1192. X  end = r[0].firstentry - 1;
  1193. X  while (l[end].type == empty)   /* suppress trailing empty lines */
  1194. X     end--;
  1195. X  }
  1196. X  for (i = 0; i <= end; i++) {  /* lines up to first ref. declaration */
  1197. X      switch (l[i].type) {
  1198. X         case refcall  :
  1199. X         case refcallr :
  1200. X                {   /* insert_refinement  (Level 1) */
  1201. X                insert_refinement (out, l+i, l[i].indent, 1);
  1202. X                if (stop_processing)
  1203. X                   return;
  1204. X                }
  1205. X                break;
  1206. X         case leave    :
  1207. X                {   /* whatshallthatbe  (Level 1) */
  1208. X                assert (false);
  1209. X                }
  1210. X                break;
  1211. X         case normal   :
  1212. X                {   /* insert_normal_line  (Level 1) */
  1213. X                put_line (out, &l[i], 0, 1);
  1214. X                }
  1215. X                break;
  1216. X         case empty    :
  1217. X                putc ('\n', out);
  1218. X                commanded_line_no++;
  1219. X                break;
  1220. X         case refdecl  :
  1221. X         default       :
  1222. X                 assert (false);
  1223. X      }
  1224. X  }
  1225. X  {   /* maybe_give_sermon_on_refinements  (Level 1) */
  1226. X  for (i = 0; i < r_pos; i++)
  1227. X      if (r[i].semicolons > 50)
  1228. X         warning (Wlong_ref, l[r[i].firstentry].start,
  1229. X                  refdecl_line (i), 3);
  1230. X      else if (r[i].calls > 5 && r[i].semicolons > 2)
  1231. X         warning (Wref_often_used, l[r[i].firstentry].start,
  1232. X                  refdecl_line (i), 3);
  1233. X      else if (r[i].calls == 0)
  1234. X         warning (Wref_unused, l[r[i].firstentry].start,
  1235. X                  refdecl_line (i), 1);
  1236. X  }
  1237. X  stop_processing = stop_processing || extern_stop;  /* Merging-Restore */
  1238. X}
  1239. X
  1240. X/************************* insert_refinement ******************************/
  1241. X
  1242. Xstatic void insert_refinement (out, z, startindent, recursive_level)
  1243. X  FILE *out;
  1244. X  LINE_INFO *z;
  1245. X  int  startindent, recursive_level;
  1246. X{
  1247. X  /* Looks for the refinement to insert by its name, computes the range
  1248. X     of lines to work on and does then do the same as insert_refinements
  1249. X     does.
  1250. X     If necessary the refinement name is given as a comment before the
  1251. X     body is inserted.
  1252. X     The refinement body is enclosed in delimiters:
  1253. X       if ref.semicolons == 0 in parentheses (on first and last line)
  1254. X       if ref.semicolons >= 1 in curly braces (on separate lines)
  1255. X     The refinement calls are counted and maybe messages generated.
  1256. X     In case of leave-statements the refinement that shall be leave'd is
  1257. X     marked, so a label can be generated.
  1258. X     Errors:
  1259. X       1. Refinement is not declared
  1260. X       2. recursive call to refinement
  1261. X       3. leave is impossible because the refinement is not
  1262. X          present in static call hierarchy
  1263. X  */
  1264. X  int i;
  1265. X  int  nr, ref_startindent, end;
  1266. X  assert (startindent > 0);
  1267. X  nr = refinement_nr ((
  1268. X  z->start)
  1269. X  );  /* search for refinement */
  1270. X  if (nr == -1) {
  1271. X     error (Eref_not_decl, (
  1272. X     z->start)
  1273. X     , z->line_no);
  1274. X     return;
  1275. X  }
  1276. X  else if (r[nr].active)
  1277. X     {   /* complain_for_recursive_refinement_call  (Level 1) */
  1278. X     error (Erecursive_ref, (
  1279. X     z->start)
  1280. X     , z->line_no);
  1281. X     stop_processing = true;
  1282. X     return;
  1283. X     }
  1284. X  else {
  1285. X     r[nr].calls++;           /* register the call */
  1286. X     r[nr].active   = true;
  1287. X     r[nr].leave_it = false;
  1288. X  }
  1289. X  end = r[nr+1].firstentry - 1;
  1290. X  while (l[end].type == empty)   /* suppress trailing empty lines */
  1291. X     end--;
  1292. X  i = r[nr].firstentry + 1;
  1293. X  if (i > end)
  1294. X     warning (Wref_empty, l[r[nr].firstentry].start, refdecl_line (nr), 2);
  1295. X  else
  1296. X     {   /* insert_the_refinement  (Level 1) */
  1297. X     /* for an empty refinement, this is not called at all! */
  1298. X     {   /* write_indentation_and_opening_klammer  (Level 2) */
  1299. X     int sc = r[nr].semicolons;
  1300. X     if (sc > 0)
  1301. X        put_indent (out, startindent);
  1302. X     putc (sc > 0 ? '{' : '(', out);  /* Klammer auf */
  1303. X     if (option_comment && sc > 0)
  1304. X        fprintf (out, Tlistline[msg_type], (
  1305. X        z->start)
  1306. X        , recursive_level);
  1307. X     }
  1308. X     ref_startindent = l[i].indent;
  1309. X     for ( ; i <= end; i++) {
  1310. X         switch (l[i].type) {
  1311. X            case refcall  :
  1312. X            case refcallr :
  1313. X                   {   /* insert_refinement  (Level 2) */
  1314. X                   insert_refinement (out, l+i,
  1315. X                                      startindent + l[i].indent
  1316. X                                                  - ref_startindent,
  1317. X                                      recursive_level+1);
  1318. X                   }
  1319. X                   break;
  1320. X            case leave    :
  1321. X                   {   /* insert_goto_statement  (Level 2) */
  1322. X                   int leave_nr = refinement_nr (l[i].start);
  1323. X                   if (leave_nr == -1)
  1324. X                      error (Eunknown_leave, l[i].start, l[i].line_no);
  1325. X                   else if (!r[leave_nr].active)
  1326. X                      error (Eleave_unpresent, l[i].start, l[i].line_no);
  1327. X                   else {
  1328. X                      r[leave_nr].leave_it = true;
  1329. X                      put_indent (out, startindent);
  1330. X                      fprintf (out, "goto %s_%d;",
  1331. X                               l[i].start, r[leave_nr].calls);
  1332. X                   }
  1333. X                   }
  1334. X                   break;
  1335. X            case normal   :
  1336. X                   {   /* insert_normal_line  (Level 2) */
  1337. X                   put_line (out, &l[i], startindent - ref_startindent, (
  1338. X                   r[nr].semicolons == 0 ? 3 : 2)
  1339. X                   );
  1340. X                   }
  1341. X                   break;
  1342. X            case empty    :
  1343. X                   putc ('\n', out);
  1344. X                   commanded_line_no++;
  1345. X                   break;
  1346. X            case refdecl  :
  1347. X            default       :
  1348. X                    assert (false);
  1349. X         }
  1350. X     }
  1351. X     if (r[nr].leave_it)
  1352. X        {   /* generate_label  (Level 2) */
  1353. X        fprintf (out, "\n%s_%d: ;", (
  1354. X        z->start)
  1355. X        , r[nr].calls);
  1356. X        commanded_line_no++;
  1357. X        }
  1358. X     {   /* write_closing_klammer  (Level 2) */
  1359. X     int sc = r[nr].semicolons;
  1360. X     if (sc > 0) {
  1361. X        put_indent (out, startindent);
  1362. X        putc ('}', out);
  1363. X     }
  1364. X     else {
  1365. X        putc (')', out);
  1366. X        if (z->type == refcallr)  /* semicolon has been removed illegaly */
  1367. X           putc (';', out);
  1368. X     }
  1369. X     }
  1370. X     }
  1371. X  r[nr].active = false;
  1372. X  return;
  1373. X}
  1374. X
  1375. X/************************* line_cmd **************************************/
  1376. X
  1377. Xstatic void line_cmd (out, nr, indent, min_level)
  1378. X  FILE *out;
  1379. X  int  nr;
  1380. X  int  indent;
  1381. X  int  min_level;
  1382. X{
  1383. X  /* Writes a "preprocessor #line directive" including file name if
  1384. X     requested.
  1385. X     Is suppressed, if min_level is less than numbering_level.
  1386. X     Using numbering_level, option_indent, commanded_line_no and name_in
  1387. X  */
  1388. X  if (numbering_level >= min_level) {
  1389. X     if (option_indent)
  1390. X        put_indent (out, indent);
  1391. X     else
  1392. X        putc ('\n', out);
  1393. X     fprintf (out, "#line %d \"%s\"", nr, modified_name_in);
  1394. X     commanded_line_no = nr-1; /* #line 3  means: next comes line 3 ! */
  1395. X  }
  1396. X}
  1397. X
  1398. X/********************** put_indent **************************************/
  1399. X
  1400. Xstatic void put_indent (out, how_far)
  1401. X  FILE *out;
  1402. X  int how_far;
  1403. X{
  1404. X  putc ('\n', out);      /* begin newline */
  1405. X  commanded_line_no++;
  1406. X  if (!option_small)
  1407. X     fwrite (blanks, how_far > 72 ? 72 : (how_far < 0 ? 0 : how_far),
  1408. X             1, out);
  1409. X}
  1410. X
  1411. X/*************************** put_line ***********************************/
  1412. X
  1413. Xstatic void put_line (out, line, additional_indent, min_level)
  1414. X  FILE       *out;
  1415. X  LINE_INFO  *line;    /* pointer for efficiency (is big object) */
  1416. X  int        additional_indent;
  1417. X  int        min_level;
  1418. X{
  1419. X  /* Writes the line 'line' to 'out' with the appropriate indentation
  1420. X     (which is the line's indentation plus additional_indent).
  1421. X     If the current line numbering is not right a line_cmd is made before.
  1422. X  */
  1423. X  if (line->line_no != commanded_line_no + 1)
  1424. X     line_cmd (out, line->line_no, line->indent + additional_indent,
  1425. X               min_level);
  1426. X  if (line->type == empty) {    /* for empty lines: nothing */
  1427. X     putc ('\n', out);
  1428. X     commanded_line_no++;
  1429. X     return;
  1430. X  }
  1431. X  else if (option_small || (!option_indent && *line->start == '#')) {
  1432. X     putc ('\n', out);
  1433. X     commanded_line_no++;
  1434. X  }
  1435. X  else
  1436. X     put_indent (out,
  1437. X                 line->indent + additional_indent);  /* starts new line */
  1438. X  assert (line->start != NULL);
  1439. X  fputs (line->start, out);
  1440. X#if debug
  1441. X  fprintf (stdout, "put:\"%s\"\n", line->start);
  1442. X#endif
  1443. X}
  1444. X
  1445. X/********************** refinement_nr ************************************/
  1446. X
  1447. Xstatic int refinement_nr (name)
  1448. X  char *name;
  1449. X{
  1450. X  /* computes the number of a refinement from its name 'name'.
  1451. X     Uses r from 0 to r_pos. Returns the number or -1 if undeclared.
  1452. X     If the refinement is declared more than once an error message is
  1453. X     generated.
  1454. X  */
  1455. X  int i, match = -1, matches = 0;
  1456. X  assert (name != NULL);
  1457. X  for (i = 0; i < r_pos; i++)
  1458. X      if (!strcmp (name, r[i].name)) {
  1459. X         match = i;
  1460. X         matches++;
  1461. X      }
  1462. X  if (matches > 1)
  1463. X     error (Eref_multi_decl, r[match].name, refdecl_line (match));
  1464. X  return (match);
  1465. X}
  1466. X
  1467. X/********************* Auxiliary functions ******************************/
  1468. X
  1469. Xstatic void copy_with_doubled_backslashes (string, copy)
  1470. X  char *string, *copy;
  1471. X{
  1472. X  /* copies the string string to the location copy. All backslash
  1473. X     characters (code 92) in string are copied twice, so for example
  1474. X     "back\slas\\h" is copied to "back\\slas\\\\h".
  1475. X     The purpose of this is to make the copy usable as a C string denoter,
  1476. X     in which the backslash is interpreted as an escape symbol.
  1477. X     No checks are made, thus there must be enough memory allocated
  1478. X     to make the copy.
  1479. X  */
  1480. X  assert (string != NULL);
  1481. X  assert (copy != NULL);
  1482. X  while (*string != 0) {
  1483. X     *copy = *string;
  1484. X     string++;
  1485. X     if (*copy == 92) {      /* is backslash ? */
  1486. X       *(copy + 1) = 92;     /* then put another and */
  1487. X       copy += 2;            /* proceed two bytes */
  1488. X     }
  1489. X     else                    /* else */
  1490. X       copy++;               /* proceed one byte */
  1491. X  }
  1492. X  *copy = 0;
  1493. X}
  1494. X
  1495. X
  1496. Xstatic void do_expire (day, month, year)
  1497. X  int day, month, year;
  1498. X{
  1499. X  long act_time;
  1500. X  struct tm *t;
  1501. X  time (&act_time);
  1502. X  t = localtime (&act_time);
  1503. X  month--;   /* localtime uses months 0 - 11 ! */
  1504. X  if ((
  1505. X  t->tm_year > year || (t->tm_year == year && t->tm_mon > month) ||
  1506. X  (t->tm_year == year && t->tm_mon == month && t->tm_mday > day))
  1507. X  ) {
  1508. X     fprintf (stderr, "\n%s\n\n", Thas_expired[msg_type]);
  1509. X     exit (100);
  1510. X  }
  1511. X}
  1512. X
  1513. X
  1514. Xstatic void reset_l_r_s ()
  1515. X{
  1516. X  /* Sets LINE_INFO- and REF_INFO-Arrays 'l' and 'r' into
  1517. X     their empty state.
  1518. X  */
  1519. X  int i;
  1520. X  for (i = 0; i <= r_pos; i++) { /* Alle Refinements loeschen */
  1521. X      r[i].name  = NULL;
  1522. X      r[i].calls = 0;
  1523. X  }
  1524. X  s = s_root;                    /* Zeilenspeicher loeschen */
  1525. X  l_pos = r_pos = old_level = 0;
  1526. X}
  1527. X
  1528. X
  1529. END_OF_FILE
  1530.   if test 30121 -ne `wc -c <'crefine.c'`; then
  1531.     echo shar: \"'crefine.c'\" unpacked with wrong size!
  1532.   fi
  1533.   # end of 'crefine.c'
  1534. fi
  1535. echo shar: End of archive 1 \(of 4\).
  1536. cp /dev/null ark1isdone
  1537. MISSING=""
  1538. for I in 1 2 3 4 ; do
  1539.     if test ! -f ark${I}isdone ; then
  1540.     MISSING="${MISSING} ${I}"
  1541.     fi
  1542. done
  1543. if test "${MISSING}" = "" ; then
  1544.     echo You have unpacked all 4 archives.
  1545.     rm -f ark[1-9]isdone
  1546. else
  1547.     echo You still must unpack the following archives:
  1548.     echo "        " ${MISSING}
  1549. fi
  1550. exit 0
  1551. exit 0 # Just in case...
  1552.